import { useDebounce } from '@gnlab/utils/env-react'
import { message } from 'antd'
import services from '@/services'
import { type ExternalItemTag, type FullSearchContact } from '@/services/contact-types'
import { getQywxs, type AccountQywx, formatAccountQywx, AccountQywxStatus } from '@/services/qywxs'

export type { AccountQywx, FullSearchContact }
export { AccountQywxStatus }

/**
 * 准备“筛选条件”数据
 */
export interface SearchTag extends ExternalItemTag {
  corpname: string
}

interface Resources {
  qywxs: AccountQywx[] | null
  tags: SearchTag[] | null
}

function useConditionResources() {
  const [resources, setResources] = useState<Resources>({ qywxs: null, tags: null })

  useEffect(() => {
    void getQywxs('', false).then(res => {
      const qywxs = res.success ? res.data.map(formatAccountQywx) : []
      setResources(resources => ({ ...resources, qywxs }))

      if (!qywxs.length) return void setResources(resources => ({ ...resources, tags: [] }))

      const corpMap = new Map(qywxs.map(qywx => [qywx.corpid, qywx.corpname]))
      void services.externals.tags.getAllTags([...corpMap.keys()]).then(res => {
        const tags = (res.success ? res.data : [])
          .filter((tag): tag is ExternalItemTag => !tag.isGroup)
          .map(tag => ({ ...tag, corpname: corpMap.get(tag.corpid) ?? '未知企业' }))
        setResources(resources => ({ ...resources, tags }))
      })
    })
  }, [])

  return resources
}

// =======================================

// 一次加载多少条搜索结果
const searchPageSize = 20

// 返回可用在 conditions 里的标签列表
function getChoosableTags(allTags: SearchTag[] | null, relatedQywx: AccountQywx | null) {
  if (!allTags) return null
  return !relatedQywx
    ? // 未选择企业微信时，只允许使用企业标签
      allTags.filter(tag => tag.isCorp)
    : // 选择了企业微信时，允许使用企业标签和此企业微信的个人标签
      allTags.filter(tag =>
        tag.isCorp ? tag.corpid === relatedQywx.corpid : tag.wxid === relatedQywx.wxid,
      )
}

interface SearchState {
  conditions: {
    keyword: string
    qywx: AccountQywx | null
    tag: SearchTag | null
  }
  loadingInfo: {
    // 加载状态
    loading: boolean // 是否正在加载
    page: number // 已加载的页码（加载成功后才会更新，0 代表还没完成过加载）
    full: boolean // 是否已完全加载
  }
  contacts: FullSearchContact[]
}

type SearchAction =
  | { type: 'update-conditions'; updates: Partial<SearchState['conditions']> } // 更新搜索条件
  | { type: 'next-page' } // 开始加载下一页
  | { type: 'loaded'; result: FullSearchContact[] } // 取得搜索结果（初始的或翻页的）

function getInitialState(conditions: SearchState['conditions']): SearchState {
  const empty = conditions.keyword === ''
  return {
    conditions,
    loadingInfo: { loading: !empty, page: 0, full: empty },
    contacts: [],
  }
}

function searchReducer(
  resources: Resources,
  state: SearchState,
  action: SearchAction,
): SearchState {
  switch (action.type) {
    case 'update-conditions': {
      const { conditions } = state
      const updated = { ...conditions, ...action.updates }

      // 若企业微信变化，重新确定筛选条件里的“标签”是否有效
      if (updated.tag && updated.qywx !== conditions.qywx) {
        const choosableTags = getChoosableTags(resources.tags, updated.qywx)
        if (!choosableTags?.find(tag => tag.id === updated.tag!.id)) updated.tag = null
      }

      return getInitialState(updated)
    }

    case 'next-page':
      return state.loadingInfo.full
        ? state
        : { ...state, loadingInfo: { ...state.loadingInfo, loading: true } }

    case 'loaded': {
      const { result } = action
      return {
        ...state,
        loadingInfo: {
          loading: false,
          page: state.loadingInfo.page + 1,
          full: result.length < searchPageSize,
        },
        contacts: [...state.contacts, ...result],
      }
    }

    default:
      throw new Error()
  }
}

export function useSearch(initialKeyword: string) {
  // 供进行筛选的数据
  const resources = useConditionResources()

  const [{ conditions, loadingInfo, contacts }, dispatch] = useReducer(
    searchReducer.bind(null, resources),
    getInitialState({ keyword: initialKeyword, qywx: null, tag: null }),
  )

  const choosableTags = getChoosableTags(resources.tags, conditions.qywx)

  // 交给外界使用的 conditions
  const conditionsForUse = {
    keyword: conditions.keyword,
    wxid: conditions.qywx?.wxid ?? null,
    tagId: conditions.tag?.id ?? null,
  }

  // conditions 更新函数
  // 对搜索关键词的更新延迟生效
  const setKeyword = useDebounce(
    (keyword: string) => dispatch({ type: 'update-conditions', updates: { keyword } }),
    500,
  )
  function setWxid(wxid: string | null) {
    const qywx =
      resources.qywxs && wxid !== null ? resources.qywxs.find(v => v.wxid === wxid) ?? null : null
    dispatch({ type: 'update-conditions', updates: { qywx } })
  }
  function setTagId(tagId: string | null) {
    const tag =
      choosableTags && tagId !== null ? choosableTags.find(t => t.id === tagId) ?? null : null
    dispatch({ type: 'update-conditions', updates: { tag } })
  }

  // 执行搜索
  function nextPage() {
    if (!loadingInfo.loading && !loadingInfo.full) dispatch({ type: 'next-page' })
  }

  useEffect(() => {
    if (!loadingInfo.loading) return

    let cancelled = false
    void services.externals.search
      .fullSearch({
        keyword: conditions.keyword,
        ownerWxid: conditions.qywx?.wxid ?? null,
        tagId: conditions.tag?.id ?? null,
        page: loadingInfo.page + 1,
        pageSize: searchPageSize,
      })
      .then(res => {
        if (cancelled) return
        if (res.success) {
          dispatch({ type: 'loaded', result: res.data })
        } else {
          void message.warning('搜索失败：' + res.error)
          dispatch({ type: 'loaded', result: [] })
        }
      })
    return () => {
      cancelled = true
    }
  }, [conditions, loadingInfo])

  return {
    qywxs: resources.qywxs,
    tags: choosableTags,
    conditions: conditionsForUse,
    setKeyword,
    setWxid,
    setTagId,
    loading: loadingInfo.loading,
    full: loadingInfo.full,
    nextPage,
    contacts,
  }
}
